﻿namespace SandScript
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Xml;
    using System.Xml.XPath;
    using Models;

    public class XmlGenerator : IXmlGenerator
    {
        public void ConvertToXml(IList<MemberDetail> memberDetails)
        {
            var document = new XmlDocument();
            var root = document.CreateElement("reflection");
            document.AppendChild(root);
            root.AppendChild(document.CreateElement("assemblies"));
            var apiList = document.CreateElement("apis");
            root.AppendChild(apiList);

            var global = new MemberDetail()
            {
                Name = "Global",
                Type = MemberType.Global,
                Members = memberDetails
            };

            AddApi(apiList, global, null);

            OutputToConsole(document);
        }

        private static void OutputToConsole(XmlDocument document)
        {
            var stringWriter = new StringWriter();
            var xmlWriter = new XmlTextWriter(stringWriter)
            {
                Formatting = Formatting.Indented,
                Indentation = 1,
                IndentChar = '\t'
            };
            document.WriteTo(xmlWriter);

            Console.WriteLine(stringWriter.ToString());
        }

        private static void AddApi(XmlElement apiList, MemberDetail detail, string parentId)
        {
            var group = "member";
            var subGroup = "field";
            var isGlobal = false;
            var hasDocumentation = false;
            XPathNavigator navigator = null;

            if (!string.IsNullOrEmpty(detail.Documentation))
            {
                try
                {
                    var documentation = new XmlDocument();
                    documentation.LoadXml("<root>" + detail.Documentation + "</root>");
                    navigator = documentation.CreateNavigator();
                    hasDocumentation = true;
                }
                catch
                {
                }
            }

            switch (detail.Type)
            {
                case MemberType.Property:
                    subGroup = "property";
                    break;
                case MemberType.Function:
                    if (char.IsUpper(detail.Name[0]))
                    {
                        group = "type";
                        subGroup = "class";
                    }
                    else
                    {
                        subGroup = "method";

                        if (hasDocumentation)
                        {
                            var returns = navigator.SelectSingleNode("returns@type");

                            if (returns != null)
                            {
                            }
                        }
                    }

                    break;
                case MemberType.Global:
                    group = "namespace";
                    subGroup = string.Empty;
                    isGlobal = true;
                    break;
            }

            var id = isGlobal ? detail.Name : string.Concat(parentId, '.', detail.Name);
            var document = apiList.OwnerDocument;
            var api = document.CreateElement("api");
            apiList.AppendChild(api);
            api.SetAttribute("id", id);
            var apiData = document.CreateElement("apidata");
            api.AppendChild(apiData);
            apiData.SetAttribute("name", detail.Name);
            apiData.SetAttribute("group", group);

            if (!string.IsNullOrEmpty(subGroup))
            {
                apiData.SetAttribute("subgroup", subGroup);
            }

            if (!isGlobal)
            {
                var containers = document.CreateElement("containers");
                api.AppendChild(containers);
                var library = document.CreateElement("library");
                containers.AppendChild(library);
                library.SetAttribute("assembly", string.Empty);
                library.SetAttribute("namespace", parentId);
                var @namespace = document.CreateElement("namespace");
                containers.AppendChild(@namespace);
                @namespace.SetAttribute("api", parentId);
            }

            if (detail.Members != null && detail.Members.Count > 0)
            {
                var elements = api.AppendChild(document.CreateElement("elements"));
                api.AppendChild(elements);

                foreach (var item in detail.Members)
                {
                    var element = document.CreateElement("element");
                    elements.AppendChild(element);
                    element.SetAttribute("api", string.Concat(id, '.', item.Name));

                    AddApi(apiList, item, id);
                }
            }
        }
    }
}
